package p2pscrabble;

import java.awt.Color;

import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class GamePanel extends JPanel {
	private BoardPanel boardPanel;
	private LetterPanel letterPanel;
	private char swapChar = '/';
	private boolean swapBlank = false;
	private boolean firstTurn = true;
	private boolean[][] currentTurn;
	private char[][] curBoardLetter;

	// determine horizontal/vertical, where the words start and end
	private boolean horizontal;
	private int word_start;
	private int word_end;
	private int row_or_col;
	private int total_tiles;
	private TilesBag bag;
	private String words;
	private String letter_pos;

	public GamePanel(TilesBag bag) {
		total_tiles = 7;
		words = "";
		letter_pos = "";
		this.bag = bag;
		boardPanel = new BoardPanel();
		letterPanel = new LetterPanel();
		drawTiles();

		if (bag.getCounter() == 6)
			bag.setCounter(13);

		this.add(boardPanel);

		this.add(letterPanel);
		letterPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
	}

	public char getSwapChar() {
		return swapChar;
	}

	public void setSwapChar(char letter) {
		swapChar = letter;
	}

	public boolean isSwapBlank() {
		return swapBlank;
	}

	public void setSwapBlank(boolean swapBlank) {
		this.swapBlank = swapBlank;
	}

	private char[][] getBoardLetter() {
		return boardPanel.getBoardLetter();
	}

	private boolean[][] getCurrentTurn() {
		return boardPanel.getCurrentTurn();
	}

	public char[] drawTiles() {
		int i;
		char l;

		for (i = 7 - total_tiles; i < 7; i++) {
			if (bag.getCounter() >= 99)
				break;
			l = bag.getLetterFromBag();
			letterPanel.drawTiles(l);
		}

		// System.out.println(bag.getCounter());
		letterPanel.rearrangeTiles();
		return letterPanel.getLetters();
	}

	public boolean checkValidSubmit() {
		if (!boardPanel.checkBlankTileFilled()) {
			new InfoWindow(1, "Error",
					"Please fill in blank tiles before submitting !");
			System.out.println("Please fill in blank tiles before submitting");
			return false;
		}

		curBoardLetter = getBoardLetter();
		currentTurn = getCurrentTurn();

		int i, j;
		int crow[] = new int[7], ccol[] = new int[7];
		total_tiles = 0;
		horizontal = false;
		letter_pos = "";
		words = "";

		// check how many tiles are put on the board
		for (i = 0; i < 15; i++) {
			for (j = 0; j < 15; j++) {
				// System.out.print(currentTurn[i][j]);
				if (currentTurn[i][j]) {
					crow[total_tiles] = i;
					ccol[total_tiles] = j;
					total_tiles++;
				}
			}
			// System.out.println();
		}

		// check if players put any tiles
		if (total_tiles < 1) {
			new InfoWindow(1, "Error", "Please play at least a tile !");
			System.out.println("You must play at least a tile!\n");
			return false;
		}

		// check if the first word is on the center
		if (!currentTurn[7][7] && firstTurn) {
			new InfoWindow(1, "Error",
					"Please put the first word on the center square !");
			System.out.println("You must put on the center square.\n");
			return false;
		}

		// check if the tiles are put in the same column / row
		if (crow[1] == crow[0]) {
			horizontal = true;
		}
		for (i = 1; i < total_tiles; i++) {
			if ((crow[i] != crow[0] && horizontal)
					|| (ccol[i] != ccol[0] && !horizontal)) {
				new InfoWindow(1, "Error",
						"Tiles must be placed in the same row or column !");
				System.out
						.println("Tiles must be placed in the same row or column.\n");
				return false;
			}
		}

		// determine the row or column of the tiles
		row_or_col = crow[0];
		word_start = ccol[0];
		word_end = ccol[0];

		// if player put more than one tiles
		if (total_tiles > 1) {
			if (horizontal) {
				row_or_col = crow[0];
				word_start = ccol[0];
				word_end = ccol[total_tiles - 1];
			} else {
				row_or_col = ccol[0];
				word_start = crow[0];
				word_end = crow[total_tiles - 1];
			}
		} else {
			// determine whether it's horizontal n vertical for counting score
			if (check_touch_cross(horizontal, crow[0], ccol[0])) {
				horizontal = true;
				row_or_col = crow[0];
				word_start = ccol[0];
				word_end = ccol[0];
			} else if (check_touch_cross(!horizontal, crow[0], ccol[0])) {
				horizontal = false;
				row_or_col = ccol[0];
				word_start = crow[0];
				word_end = crow[0];
			}
			// first turn with only 1 tile put
			else if (firstTurn) {
				return true;
			}
			// the tile is not besides the existing tiles
			else {
				new InfoWindow(1, "Error",
						"Please put the tile besides the existing ones !");
				System.out
						.println("Please put the tile besides the existing ones.");
				return false;
			}
		}

		// start, end = column if horizontal, or equals to row number if
		// vertical

		if (total_tiles > 1) {
			if (!check_continuous(horizontal, word_start, word_end, row_or_col)) {
				new InfoWindow(1, "Error", "Please put the word in one line !");
				System.out.println("You must put the word in one line.");
				return false;
			} else if (word_end - word_start > total_tiles) {
			} else if (!check_continuous_with_other_tiles(horizontal,
					word_start, word_end, row_or_col)) {
				new InfoWindow(1, "Error",
						"Please put the tile besides the existing ones !");
				System.out
						.println("You must put the tiles besides the existing ones.");
				return false;
			}

			// System.out.println(horizontal + " " + word_start + " " + word_end
			// + " " + row_or_col);
		}

		word_start = start_of_word(horizontal, row_or_col, word_start);
		word_end = end_of_word(horizontal, row_or_col, word_end);

		for (i = 0; i < total_tiles; i++) {
			int pos = crow[i] * 100 + ccol[i];
			if (letter_pos != "")
				letter_pos += ",";
			letter_pos += curBoardLetter[crow[i]][ccol[i]] + ":"
					+ Integer.toString(pos);
		}

		return true;
	}

	// determine start of word
	private int start_of_word(boolean hor, int row_or_col, int word_start) {
		int i, start;

		start = word_start;

		// see if there is more letters before current start
		if (hor) {
			for (i = start; i >= 0; i--) {
				if (curBoardLetter[row_or_col][i] != ' ')
					start = i;
				else
					break;
			}
		} else {
			for (i = start; i >= 0; i--) {
				if (curBoardLetter[i][row_or_col] != ' ')
					start = i;
				else
					break;
			}
		}
		return start;
	}

	// determine end of word
	private int end_of_word(boolean hor, int row_or_col, int word_end) {
		int i, end;
		end = word_end;

		if (hor) {
			for (i = end; i < 15; i++) {
				if (curBoardLetter[row_or_col][i] != ' ')
					end = i;
				else
					break;
			}
		} else {
			for (i = end; i < 15; i++) {
				if (curBoardLetter[i][row_or_col] != ' ')
					end = i;
				else
					break;
			}
		}
		return end;
	}

	// check if the words is continuous and links with other tiles in board
	private boolean check_continuous(boolean hor, int start, int end,
			int row_or_col) {
		int i;
		// from start to end, there should be continuous tiles
		for (i = start; i < end; i++) {
			if (hor) {
				if (curBoardLetter[row_or_col][i] == ' ') {
					return false;
				}
			} else {
				if (curBoardLetter[i][row_or_col] == ' ') {
					return false;
				}
			}
		}

		return true;
	}

	// check if the word is connected to other tiles on the scrabble board
	private boolean check_continuous_with_other_tiles(boolean hor, int start,
			int end, int row_or_col) {
		if (firstTurn)
			return true;

		int i;
		// System.out.println(hor + " " + start + " " + end + " " + row_or_col);

		if (check_touch_in_line(hor, row_or_col, start, end))
			return true;

		for (i = start; i <= end; i++) {
			if (hor) {
				if (check_touch_cross(hor, row_or_col, i)) {
					return true;
				}
			} else {
				if (check_touch_cross(hor, i, row_or_col)) {
					return true;
				}
			}
		}

		return false;
	}

	private boolean check_touch_in_line(boolean hor, int row_or_col, int start,
			int end) {
		if (hor) {
			if (start != 0) {
				if (curBoardLetter[row_or_col][start - 1] != ' ')
					return true;
			}
			if (end != 14) {
				if (curBoardLetter[row_or_col][end + 1] != ' ')
					return true;
			}
		} else {
			if (start != 0) {
				if (curBoardLetter[start - 1][row_or_col] != ' ')
					return true;
			}
			if (end != 14) {
				if (curBoardLetter[end + 1][row_or_col] != ' ')
					return true;
			}
		}
		return false;
	}

	private boolean check_touch_cross(boolean hor, int row, int col) {
		boolean check = false;
		if (hor) {
			if (row != 0) {
				if (curBoardLetter[row - 1][col] != ' ')
					check = true;
			}
			if (row != 14) {
				if (curBoardLetter[row + 1][col] != ' ')
					check = true;
			}
		} else {
			if (col != 0) {
				if (curBoardLetter[row][col - 1] != ' ')
					check = true;
			}
			if (col != 14) {
				if (curBoardLetter[row][col + 1] != ' ')
					check = true;
			}
		}
		return check;
	}

	public String submitWords() {
		int i;
		int start;
		int end;
		int score = 0;
		// System.out.println(horizontal + " " + word_start + " " + word_end);
		score = boardPanel.computeScore(horizontal, row_or_col, word_start,
				word_end);
		words = boardPanel
				.getWord(horizontal, row_or_col, word_start, word_end);

		for (i = word_start; i <= word_end; i++) {
			// find the words that are formed by crossing another word
			if ((currentTurn[row_or_col][i] && horizontal)
					|| (currentTurn[i][row_or_col] && !horizontal)) {
				start = start_of_word(!horizontal, i, row_or_col);
				end = end_of_word(!horizontal, i, row_or_col);

				if (end != start) {
					score += boardPanel
							.computeScore(!horizontal, i, start, end);
					words += ";"
							+ boardPanel.getWord(!horizontal, i, start, end);
				}
			}
		}
		if (total_tiles == 7)
			score += 50;

		words = score + ";" + letter_pos + ";" + words;
		System.out.println(words);

		return words;
	}

	public boolean swapLetters() {
		int i;
		int j;
		total_tiles = 0;
		int[] crow = new int[7];
		int[] ccol = new int[7];

		if (bag.getCounter() >= 93) {
			new InfoWindow(1, "Error",
					"You cannot swap when there are less than 7 tiles left!");
			return false;
		}

		curBoardLetter = getBoardLetter();
		currentTurn = getCurrentTurn();

		// check how many tiles are put on the board
		for (i = 0; i < 15; i++) {
			for (j = 0; j < 15; j++) {
				if (currentTurn[i][j]) {
					crow[total_tiles] = i;
					ccol[total_tiles] = j;
					total_tiles++;
				}
			}
		}

		if (total_tiles == 0) {
			new InfoWindow(1, "Error",
					"Please place tiles on the board before clicking swap button!");
			return false;
		}

		for (i = 0; i < total_tiles; i++) {
			boardPanel.removeTile(crow[i], ccol[i]);
			char l = bag.swapAction(curBoardLetter[crow[i]][ccol[i]], i);
			letterPanel.drawTiles(l);
			letterPanel.rearrangeTiles();
		}

		total_tiles = 0;
		bag.shuffleLetters();

		return true;
	}

	public void submitOppTiles(char[] letters, int[] row, int[] col) {
		boardPanel.submitOppTiles(letters, row, col);
	}

	public void setBoardEnabled(boolean b) {
		boardPanel.setEnabled(b);
		boardPanel.setBoardTileEnable(b);
	}

	public void finish_submit() {
		boardPanel.removeRedLine();
		for (int i = word_start; i <= word_end; i++) {
			if (horizontal) {
				boardPanel.setTileFixed(row_or_col, i);
			} else {
				boardPanel.setTileFixed(i, row_or_col);
			}
		}
	}

	public void setFirstTurn(boolean b) {
		firstTurn = b;
	}

	public char[][] getCurBoardLetter() {
		return curBoardLetter;
	}

	public void setTiles(char[][] boardLetters, char[] myLetters) {
		firstTurn = true;

		for (int i = 0; i < 15; i++) {
			for (int j = 0; j < 15; j++) {
				if (boardLetters[i][j] != ' ') {
					firstTurn = false;
					break;
				}
			}
		}

		boardPanel.setBoardTiles(boardLetters);
		letterPanel.setLetterTiles(myLetters);
	}

	public void clearBoard(char[][] boardLetters, char[] letters) {
		boardPanel.returnToHand();
		letterPanel.setLetterTiles(letters);
	}
}
